package demoMod.anm2editor.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.math.MathUtils;
import demoMod.anm2editor.enums.CustomPathType;
import demoMod.anm2editor.enums.LayerType;
import demoMod.anm2editor.fonts.FontKeys;
import demoMod.anm2editor.localization.LocalizedStrings;
import demoMod.anm2editor.model.*;
import demoMod.anm2editor.utils.Preferences;
import demoMod.gdxform.abstracts.Container;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.helpers.FontHelper;
import demoMod.gdxform.interfaces.Element;
import demoMod.gdxform.interfaces.MouseEventSubscriber;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class PreviewPane extends Container<Element> implements MouseEventSubscriber {
    public static final String ID = "PreviewPane";
    private float offsetX = 0.0F;
    private float offsetY = 0.0F;
    private float scale = 1.0F;
    private boolean mouseDown = false;
    private final Timeline timeline = (Timeline) FormManager.getInstance().getContainerById(Timeline.ID);
    private final Texture guide;
    private final Texture axis;
    private final ToolBar toolBar;
    private final KeyFramePropertyPanel keyFramePropertyPanel;
    private final HistoryPanel historyPanel;
    private KeyFrame stateBeforeOperation;
    private KeyFrame target;
    private PathCurve pathCurve;
    private List<Anchor> pathLengthCache;
    private float cachedCurveLength;
    private List<Float> cachedLineDistance;
    private List<KeyFrame> bakedFrames;
    private Anchor currentSelectedAnchor;
    private Interpolation progressCurve = Interpolation.linear;
    private boolean startDraggingGuide = false;
    private Anchor currentSelectedGuideAnchor;

    public PreviewPane() {
        setBackground(getBackground());
        setId(ID);
        Pixmap pixmap = new Pixmap(9, 9, Pixmap.Format.RGBA8888);
        pixmap.setColor(Color.WHITE);
        pixmap.drawLine(4, 0, 4, 8);
        pixmap.drawLine(0, 4, 8, 4);
        pixmap.drawCircle(4, 4, 4);
        guide = new Texture(pixmap);
        pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
        pixmap.setColor(Color.WHITE);
        pixmap.fill();
        axis = new Texture(pixmap);
        toolBar = (ToolBar) FormManager.getInstance().getContainerById(ToolBar.ID);
        keyFramePropertyPanel = (KeyFramePropertyPanel) FormManager.getInstance().getContainerById(KeyFramePropertyPanel.ID);
        historyPanel = (HistoryPanel) FormManager.getInstance().getContainerById(HistoryPanel.ID);
    }

    @Override
    public void render(SpriteBatch sb) {
        if (!this.visible()) return;
        getFrameBuffer().begin();
        sb.setColor(Color.WHITE);
        Gdx.gl20.glClearColor(0.0F, 0.0F, 0.0F, 0.0F);
        Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
        List<Track> trackList = new ArrayList<>(Project.currentProject.getTracks());
        Collections.reverse(trackList);
        int currentFrame = timeline.getPointerIndex();
        for (Track track : trackList) {
            int index = 0;
            if (!track.getContent(Project.currentProject.getCurrentAnimation().getName()).isVisible()) continue;
            TrackContent trackContent = track.getContent(Project.currentProject.getCurrentAnimation().getName());
            if (trackContent != null) {
                KeyFrame keyFrame = null;
                int i;
                for (i=0;i<trackContent.getKeyFrames().size();i++) {
                    keyFrame = trackContent.getKeyFrames().get(i);
                    if (currentFrame >= index && currentFrame < index + keyFrame.delay) break;
                    index += keyFrame.delay;
                }
                if (keyFrame != null && keyFrame.visible) {
                    KeyFrame nextFrame;
                    if (i >= trackContent.getKeyFrames().size() - 1 || !keyFrame.interpolated) {
                        nextFrame = keyFrame;
                    } else {
                        nextFrame = trackContent.getKeyFrames().get(i + 1);
                    }
                    KeyFrame interFrame = applyInterpolation(keyFrame, nextFrame, index);
                    SpriteSheet spriteSheet = Project.currentProject.getSpriteSheet(track.getSpriteSheetId());
                    Texture sprite = null;
                    if (spriteSheet != null) {
                        sprite = spriteSheet.getSprite();
                    }
                    if (sprite != null) {
                        Color finalColor = interFrame.tint.cpy();
                        finalColor.r += interFrame.colorOffset.r;
                        finalColor.g += interFrame.colorOffset.g;
                        finalColor.b += interFrame.colorOffset.b;
                        if (finalColor.r > 1.0F) {
                            finalColor.r -= 1.0F;
                        }
                        if (finalColor.g > 1.0F) {
                            finalColor.g -= 1.0F;
                        }
                        if (finalColor.b > 1.0F) {
                            finalColor.b -= 1.0F;
                        }
                        sb.setColor(finalColor);
                        sb.draw(sprite,
                                Gdx.graphics.getWidth() / 2.0F + offsetX + interFrame.xPosition * this.scale - interFrame.xPivot,
                                Gdx.graphics.getHeight() / 2.0F + offsetY - interFrame.yPosition * this.scale - (interFrame.height - interFrame.yPivot),
                                interFrame.xPivot,
                                interFrame.height - interFrame.yPivot,
                                interFrame.width,
                                interFrame.height,
                                this.scale * interFrame.xScale / 100.0F,
                                this.scale * interFrame.yScale / 100.0F,
                                -interFrame.rotation,
                                interFrame.xCrop,
                                interFrame.yCrop,
                                interFrame.width,
                                interFrame.height,
                                false, false);
                    }
                    if (Preferences.getPreferences().displayGuide()) {
                        if (track.getLayerType() == LayerType.LAYER) {
                            sb.setColor(Color.BLUE);
                        } else {
                            sb.setColor(Color.RED);
                        }
                        if (timeline.getCurrentSelectedTrack() == track) {
                            sb.setColor(Color.GREEN);
                        }
                        sb.draw(guide, Gdx.graphics.getWidth() / 2.0F + offsetX + interFrame.xPosition * this.scale + interFrame.xPivot * (this.scale - 1.0F) - 4.5F * this.scale,
                                Gdx.graphics.getHeight() / 2.0F + offsetY - interFrame.yPosition * this.scale + (interFrame.height - interFrame.yPivot) * (this.scale - 1.0F) - 4.5F * this.scale,
                                interFrame.xPivot, interFrame.height - interFrame.yPivot, 9, 9, this.scale, this.scale, 0, 0, 0, 9, 9, false, false);
                    }
                }
            }
        }
        if (Preferences.getPreferences().isPathEditMode() && pathCurve != null && bakedFrames != null) {
            sb.setColor(Color.GREEN);
            for (Anchor anchor : getPathLengthCache()) {
                if (pathLengthCache.indexOf(anchor) < pathLengthCache.size() - 1) {
                    Anchor nextAnchor = pathLengthCache.get(pathLengthCache.indexOf(anchor) + 1);
                    sb.draw(axis, Gdx.graphics.getWidth() / 2.0F + anchor.getX() * this.scale + offsetX, Gdx.graphics.getHeight() / 2.0F + anchor.getY() * this.scale + offsetY, 2, 2, (float) Math.sqrt(
                            (nextAnchor.getX() - anchor.getX()) * (nextAnchor.getX() - anchor.getX()) + (nextAnchor.getY() - anchor.getY()) * (nextAnchor.getY() - anchor.getY())
                    ), 3, this.scale, 1, MathUtils.radiansToDegrees * MathUtils.atan2(nextAnchor.getY() - anchor.getY(), nextAnchor.getX() - anchor.getX()), 0, 0, 1, 1, false, false);
                }
            }
            sb.setColor(Color.RED);
            for (int i=0;i<bakedFrames.size();i++) {
                float progress = progressCurve.apply(i / (float) bakedFrames.size());
                Anchor anchor = getPointAtProgress(progress);
                sb.draw(axis, Gdx.graphics.getWidth() / 2.0F + anchor.getX() * this.scale + offsetX, Gdx.graphics.getHeight() / 2.0F + anchor.getY() * this.scale + offsetY, 3, 3, 5, 5, 1, 1, 0, 0, 0, 1, 1, false, false);
                bakedFrames.get(i).xPosition = anchor.getX();
                bakedFrames.get(i).yPosition = -anchor.getY();
            }
            int index = 1;
            for (Anchor anchor : pathCurve.getAnchors()) {
                sb.setColor(anchor == currentSelectedAnchor ? Color.PURPLE : Color.TEAL);
                float pointDrawX = Gdx.graphics.getWidth() / 2.0F + anchor.getX() * this.scale + offsetX;
                float pointDrawY = Gdx.graphics.getHeight() / 2.0F + anchor.getY() * this.scale + offsetY;
                sb.draw(axis, pointDrawX, pointDrawY, 1, 1, 3, 3, 1, 1, 0, 0, 0, 1, 1, false, false);
                if (pathCurve.getPathType() == CustomPathType.PEN) {
                    for (Anchor guideAnchor : anchor.getBezierPoints()) {
                        float anchorX = Gdx.graphics.getWidth() / 2.0F + offsetX + (guideAnchor.getX() - 1.5F) * this.scale;
                        float anchorY = Gdx.graphics.getHeight() / 2.0F + offsetY + (guideAnchor.getY() - 1.5F) * this.scale;
                        sb.setColor(Color.BLACK);
                        sb.draw(axis, anchorX, anchorY, 2, 2, 3, 3, 1, 1, 0, 0, 0, 5, 5, false, false);
                        sb.setColor(Color.WHITE);
                        sb.draw(axis, anchorX + 2, anchorY + 2, 0, 0, (float) Math.sqrt(
                                (anchorX - pointDrawX) * (anchorX - pointDrawX) + (anchorY - pointDrawY) * (anchorY - pointDrawY)
                        ), 1, 1, 1, MathUtils.radiansToDegrees * MathUtils.atan2(pointDrawY - anchorY, pointDrawX - anchorX), 0, 0, 1, 1, false, false);
                    }
                }
                FontHelper.getFont(FontKeys.SIM_HEI_14).setColor(Color.WHITE);
                FontHelper.getFont(FontKeys.SIM_HEI_14).draw(sb, Integer.toString(index), Gdx.graphics.getWidth() / 2.0F + anchor.getX() * this.scale + offsetX, Gdx.graphics.getHeight() / 2.0F + anchor.getY() * this.scale + offsetY);
                index++;
            }
        }
        if (Preferences.getPreferences().displayGuide()) {
            sb.setColor(Color.SKY);
            sb.draw(this.axis, 0, Gdx.graphics.getHeight() / 2.0F + offsetY, Gdx.graphics.getWidth(), 1);
            sb.draw(this.axis, Gdx.graphics.getWidth() / 2.0F + offsetX, 0, 1, Gdx.graphics.getHeight());
        }
        sb.setColor(Color.WHITE);
        List<String> eventToDisplay = new ArrayList<>();
        for (Event event : Project.currentProject.getEvents()) {
            if (Project.currentProject.getCurrentAnimation() == null) break;
            List<Integer> usages = event.getUsages().getOrDefault(Project.currentProject.getCurrentAnimation().getName(), new ArrayList<>());
            for (Integer i : usages) {
                if (i == currentFrame) {
                    eventToDisplay.add(event.getName());
                }
            }
        }
        FontHelper.getFont(FontKeys.SIM_HEI_18).setColor(Color.WHITE);
        float eventY = Gdx.graphics.getHeight() * 0.8F;
        for (String eventName : eventToDisplay) {
            FontHelper.getFont(FontKeys.SIM_HEI_18).draw(sb, eventName, Gdx.graphics.getWidth() * 0.15F, eventY);
            eventY -= Gdx.graphics.getHeight() * 0.04F;
        }
        FontHelper.getFont(FontKeys.SIM_HEI_20).draw(sb, String.format("%d%%", (int)(this.scale * 100)), Gdx.graphics.getWidth() * 0.05F, Gdx.graphics.getHeight() * 0.9F);
        sb.flush();
        for (Element element : getElements()) {
            element.render(sb);
        }
        sb.flush();
        getFrameBuffer().end();
        Texture texture = getFrameBuffer().getColorBufferTexture();
        sb.setColor(Color.WHITE);
        sb.draw(texture,
                getX(true) - this.getBorderWidth(), getY(true) - this.getBorderWidth(),
                0, 0,
                getWidth() + this.getBorderWidth() * 2, getHeight() + this.getBorderWidth() * 2,
                1, 1,
                0,
                (int) getX(true) - (int) this.getBorderWidth(), (int) getY(true) - (int) this.getBorderWidth(),
                (int) getWidth() + (int) this.getBorderWidth() * 2, (int) getHeight() + (int) this.getBorderWidth() * 2,
                false, true);
        sb.flush();
    }

    public void clearPathCache() {
        pathLengthCache = null;
        CustomPathType.PEN.clearCache();
    }

    private List<Anchor> getPathLengthCache() {
        if (pathLengthCache == null) {
            pathLengthCache = new ArrayList<>();
            cachedLineDistance = new ArrayList<>();
            cachedCurveLength = 0.0F;
            for (float t=0.0F;t<1.0F;t+=0.02F) {
                Anchor anchor = pathCurve.apply(t);
                Anchor nextAnchor = pathCurve.apply(t + 0.02F);
                if (t + 0.02F < 1.0F) {
                    cachedLineDistance.add((float) Math.sqrt(Math.pow(anchor.getX() - nextAnchor.getX(), 2) + Math.pow(anchor.getY() - nextAnchor.getY(), 2)));
                    cachedCurveLength += cachedLineDistance.get(cachedLineDistance.size() - 1);
                }
                pathLengthCache.add(anchor);
            }
        }
        return pathLengthCache;
    }

    private Anchor getPointAtProgress(float a) {
        List<Anchor> cache = getPathLengthCache();
        float target = cachedCurveLength * a;
        int index = 0;
        for (Float dist : cachedLineDistance) {
            if (target - dist <= 0.0F) {
                Anchor start = cache.get(index);
                Anchor end = cache.get(index + 1);
                Anchor ret = new Anchor();
                ret.setX(Interpolation.linear.apply(start.getX(), end.getX(), target / dist));
                ret.setY(Interpolation.linear.apply(start.getY(), end.getY(), target / dist));
                return ret;
            }
            target -= dist;
            index++;
        }
        Anchor ret = new Anchor();
        ret.setX(cache.get(cache.size() - 1).getX());
        ret.setY(cache.get(cache.size() - 1).getY());
        return ret;
    }

    private KeyFrame applyInterpolation(KeyFrame currentFrame, KeyFrame nextFrame, int currFrameStartIndex) {
        KeyFrame currFrame = currentFrame.makeCopy();
        currFrame.xPosition = Interpolation.linear.apply(currFrame.xPosition, nextFrame.xPosition, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.yPosition = Interpolation.linear.apply(currFrame.yPosition, nextFrame.yPosition, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.xPivot = (int) Interpolation.linear.apply(currFrame.xPivot, nextFrame.xPivot, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.yPivot = (int) Interpolation.linear.apply(currFrame.yPivot, nextFrame.yPivot, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.xScale = Interpolation.linear.apply(currFrame.xScale, nextFrame.xScale, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.yScale = Interpolation.linear.apply(currFrame.yScale, nextFrame.yScale, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.tint.r = Interpolation.linear.apply(currFrame.tint.r, nextFrame.tint.r, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.tint.g = Interpolation.linear.apply(currFrame.tint.g, nextFrame.tint.g, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.tint.b = Interpolation.linear.apply(currFrame.tint.b, nextFrame.tint.b, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.tint.a = Interpolation.linear.apply(currFrame.tint.a, nextFrame.tint.a, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.colorOffset.r = Interpolation.linear.apply(currFrame.colorOffset.r, nextFrame.colorOffset.r, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.colorOffset.g = Interpolation.linear.apply(currFrame.colorOffset.g, nextFrame.colorOffset.g, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.colorOffset.b = Interpolation.linear.apply(currFrame.colorOffset.b, nextFrame.colorOffset.b, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        currFrame.rotation = Interpolation.linear.apply(currFrame.rotation, nextFrame.rotation, (float) (timeline.getPointerIndex() - currFrameStartIndex) / currFrame.delay);
        return currFrame;
    }

    public PathCurve getPathCurve() {
        return pathCurve;
    }

    public void setPathCurve(PathCurve pathCurve) {
        this.pathCurve = pathCurve;
    }

    public void setBakedFrames(List<KeyFrame> bakedFrames) {
        this.bakedFrames = bakedFrames;
    }

    public void setProgressCurve(Interpolation progressCurve) {
        this.progressCurve = progressCurve;
    }

    public Anchor getCurrentSelectedAnchor() {
        return currentSelectedAnchor;
    }

    public void setCurrentSelectedAnchor(Anchor currentSelectedAnchor) {
        this.currentSelectedAnchor = currentSelectedAnchor;
    }

    @Override
    public float getWidth() {
        return Gdx.graphics.getWidth();
    }

    @Override
    public float getHeight() {
        return Gdx.graphics.getHeight();
    }

    @Override
    public Color getBackground() {
        return Color.DARK_GRAY.cpy();
    }

    @Override
    public boolean clickDown(int screenX, int screenY, int button) {
        if (screenX > getX(true) && screenX < getX(true) + getWidth() && Gdx.graphics.getHeight() - screenY > getY(true)
                && Gdx.graphics.getHeight() - screenY < getY(true) + getHeight()) {
            mouseDown = true;
            List<Element> elements = this.getElements();
            for(int i = elements.size() - 1; i >= 0; --i) {
                Element element = elements.get(i);
                if (element instanceof MouseEventSubscriber && ((MouseEventSubscriber)element).clickDown(screenX, screenY, button)) {
                    return true;
                }
            }
            KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
            if (Preferences.getPreferences().isPathEditMode() && pathCurve != null && bakedFrames != null) {
                for (Anchor anchor : pathCurve.getAnchors()) {
                    for (Anchor guide : anchor.getBezierPoints()) {
                        if (Math.abs(Gdx.graphics.getWidth() / 2.0F + guide.getX() * this.scale + offsetX - screenX) <= 5.0F
                                && Math.abs(Gdx.graphics.getHeight() / 2.0F + guide.getY() * this.scale + offsetY - Gdx.graphics.getHeight() + screenY) <= 5.0F) {
                            startDraggingGuide = true;
                            currentSelectedGuideAnchor = guide;
                        }
                    }
                    if (Math.abs(Gdx.graphics.getWidth() / 2.0F + anchor.getX() * this.scale + offsetX - screenX) <= 5.0F
                            && Math.abs(Gdx.graphics.getHeight() / 2.0F + anchor.getY() * this.scale + offsetY - Gdx.graphics.getHeight() + screenY) <= 5.0F) {
                        currentSelectedAnchor = anchor;
                        return false;
                    }
                }
                return false;
            }
            if (toolBar.getSelectedIndex() > 0 && toolBar.getSelectedIndex() < 5 && keyFrame != null) {
                stateBeforeOperation = keyFrame.makeCopy();
                target = keyFrame;
            }
        }
        return false;
    }

    @Override
    public boolean clickUp(int screenX, int screenY, int button) {
        if (!this.mouseDown) return false;
        this.mouseDown = false;
        List<Element> elements = this.getElements();

        for(int i = elements.size() - 1; i >= 0; --i) {
            Element element = elements.get(i);
            if (element instanceof MouseEventSubscriber && ((MouseEventSubscriber)element).clickUp(screenX, screenY, button)) {
                break;
            }
        }
        if (Preferences.getPreferences().isPathEditMode() && pathCurve != null && bakedFrames != null) {
            startDraggingGuide = false;
            return false;
        }
        KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
        if (toolBar.getSelectedIndex() > 0 && toolBar.getSelectedIndex() < 5 && keyFrame != null) {
            KeyFrame stateBeforeOperation = this.stateBeforeOperation.makeCopy();
            KeyFrame stateAfterOperation = keyFrame.makeCopy();
            KeyFrame target = this.target;
            clearPathCache();
            Operation operation = new Operation() {
                @Override
                public void undo() {
                    if (stateBeforeOperation != null && target != null) {
                        target.xPosition = stateBeforeOperation.xPosition;
                        target.yPosition = stateBeforeOperation.yPosition;
                        target.xPivot = stateBeforeOperation.xPivot;
                        target.yPivot = stateBeforeOperation.yPivot;
                        target.xCrop = stateBeforeOperation.xCrop;
                        target.yCrop = stateBeforeOperation.yCrop;
                        target.width = stateBeforeOperation.width;
                        target.height = stateBeforeOperation.height;
                        target.xScale = stateBeforeOperation.xScale;
                        target.yScale = stateBeforeOperation.yScale;
                        target.delay = stateBeforeOperation.delay;
                        target.visible = stateBeforeOperation.visible;
                        target.tint = stateBeforeOperation.tint;
                        target.colorOffset = stateBeforeOperation.colorOffset;
                        target.rotation = stateBeforeOperation.rotation;
                        target.interpolated = stateBeforeOperation.interpolated;
                        keyFramePropertyPanel.refreshKeyFrameProperty();
                    }
                }

                @Override
                public void redo() {
                    if (stateAfterOperation != null && target != null) {
                        target.xPosition = stateAfterOperation.xPosition;
                        target.yPosition = stateAfterOperation.yPosition;
                        target.xPivot = stateAfterOperation.xPivot;
                        target.yPivot = stateAfterOperation.yPivot;
                        target.xCrop = stateAfterOperation.xCrop;
                        target.yCrop = stateAfterOperation.yCrop;
                        target.width = stateAfterOperation.width;
                        target.height = stateAfterOperation.height;
                        target.xScale = stateAfterOperation.xScale;
                        target.yScale = stateAfterOperation.yScale;
                        target.delay = stateAfterOperation.delay;
                        target.visible = stateAfterOperation.visible;
                        target.tint = stateAfterOperation.tint;
                        target.colorOffset = stateAfterOperation.colorOffset;
                        target.rotation = stateAfterOperation.rotation;
                        target.interpolated = stateAfterOperation.interpolated;
                        keyFramePropertyPanel.refreshKeyFrameProperty();
                    }
                }
            };
            List<String> strings = LocalizedStrings.getStrings(ID);
            switch (toolBar.getSelectedIndex()) {
                case 1:
                    operation.setName(strings.get(0));
                    break;
                case 2:
                    operation.setName(strings.get(1));
                    break;
                case 3:
                    operation.setName(strings.get(2));
                    break;
                case 4:
                    operation.setName(strings.get(3));
                    break;
            }
            historyPanel.addOperation(operation);
        }
        return true;
    }

    @Override
    public boolean mouseDragged(int screenX, int screenY) {
        List<Element> elements = getElements();
        for (int i=elements.size() - 1;i >= 0;i--) {
            Element element = elements.get(i);
            if (element instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) element).mouseDragged(screenX, screenY)) {
                    return true;
                }
            }
        }
        if (Preferences.getPreferences().isPathEditMode() && pathCurve != null && bakedFrames != null) {
            if (currentSelectedAnchor != null) {
                if (pathCurve.getPathType() == CustomPathType.PEN) {
                    for (Anchor anchor : currentSelectedAnchor.getBezierPoints()) {
                        if (startDraggingGuide && currentSelectedGuideAnchor == anchor) {
                            anchor.setX(anchor.getX() + Gdx.input.getDeltaX() * (1.0F / this.scale));
                            anchor.setY(anchor.getY() - Gdx.input.getDeltaY() * (1.0F / this.scale));
                            clearPathCache();
                            return false;
                        }
                    }
                }
                for (Anchor anchor : currentSelectedAnchor.getBezierPoints()) {
                    anchor.setX(anchor.getX() + Gdx.input.getDeltaX() * (1.0F / this.scale));
                    anchor.setY(anchor.getY() - Gdx.input.getDeltaY() * (1.0F / this.scale));
                }
                currentSelectedAnchor.setX(currentSelectedAnchor.getX() + Gdx.input.getDeltaX() * (1.0F / this.scale));
                currentSelectedAnchor.setY(currentSelectedAnchor.getY() - Gdx.input.getDeltaY() * (1.0F / this.scale));
                clearPathCache();
            }
            return false;
        }
        switch (toolBar.getSelectedIndex()) {
            case 0: //拖动
                offsetX += Gdx.input.getDeltaX();
                offsetY -= Gdx.input.getDeltaY();
                break;
            case 1: //移动
                KeyFrame keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (keyFrame != null) {
                    keyFrame.xPosition += Gdx.input.getDeltaX() * (1.0F / this.scale);
                    keyFrame.yPosition += Gdx.input.getDeltaY() * (1.0F / this.scale);
                    keyFramePropertyPanel.refreshKeyFrameProperty();
                }
                break;
            case 2: //缩放
                keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (keyFrame != null) {
                    float xScaleBefore = keyFrame.xScale;
                    keyFrame.xScale += (Gdx.input.getDeltaX() - Gdx.input.getDeltaY()) * (1.0F / this.scale);
                    keyFrame.yScale *= xScaleBefore == 0 ? 1.0F : keyFrame.xScale / xScaleBefore;
                    keyFramePropertyPanel.refreshKeyFrameProperty();
                }
                break;
            case 3: //旋转
                keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (keyFrame != null) {
                    float frameX = Gdx.graphics.getWidth() / 2.0F + offsetX + keyFrame.xPosition * this.scale - keyFrame.xPivot;
                    float frameY = Gdx.graphics.getHeight() / 2.0F + offsetY - keyFrame.yPosition * this.scale - (keyFrame.height - keyFrame.yPivot);
                    float lastX = Gdx.input.getX() - Gdx.input.getDeltaX();
                    float lastY = Gdx.graphics.getHeight() - Gdx.input.getY() + Gdx.input.getDeltaY();
                    float angle1 = MathUtils.atan2(Math.abs(frameY - lastY), Math.abs(frameX - lastX));
                    float angle2 = MathUtils.atan2(Math.abs(frameY - Gdx.graphics.getHeight() + Gdx.input.getY()), Math.abs(frameX - Gdx.input.getX()));
                    keyFrame.rotation -= (angle2 - angle1) * MathUtils.radiansToDegrees;
                    keyFramePropertyPanel.refreshKeyFrameProperty();
                }
                break;
            case 4: //移动中心点
                keyFrame = timeline.getCurrentSelectedKeyFrame();
                if (keyFrame != null) {
                    keyFrame.xPivot += Gdx.input.getDeltaX() * (1.0F / this.scale);
                    keyFrame.yPivot += Gdx.input.getDeltaY() * (1.0F / this.scale);
                    keyFrame.xPosition += Gdx.input.getDeltaX() * (1.0F / this.scale);
                    keyFrame.yPosition += Gdx.input.getDeltaY() * (1.0F / this.scale);
                    keyFramePropertyPanel.refreshKeyFrameProperty();
                }
                break;
        }

        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        if (!this.visible()) return false;
        List<Element> elements = getElements();
        for (int i=elements.size() - 1;i >= 0;i--) {
            Element element = elements.get(i);
            if (element instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) element).scrolled(amount)) {
                    return true;
                }
            }
        }
        this.scale += amount * 0.1F;
        return false;
    }

    @Override
    public boolean moveToElementBorder(Element element) {
        return false;
    }

    @Override
    public int getPriority() {
        return Integer.MIN_VALUE;
    }
}
